//
//  BaseViewModel.swift
//  imprint
//
//  Created by 小柠檬🍋 on 2025/3/27.
//

import Foundation
import LeanCloud


//BaseViewModel
//一定要继承 ObservableObject
class BaseViewModel : NotificationObservableObject {
    @Published var noMore = false
    @Published var footerRefreshing = false
    @Published var isInit = false
    var taskManager = TaskManager()
    var pageNo = 0
    var pageSize = 20
    private let tag = "request"
    
    public func request<T>(
        isLoading: Bool = true,
        timeout: TimeInterval = 30,
        block: @escaping () async throws-> T,
        suc: @escaping (T) -> Void,
        fail:@escaping(ServerException) -> Void
    ) {
        let task = Task {
            do {
                if isLoading {
                    showLoadPopup()
                }
                let result = try await withTimeout(timeout: timeout) {
                    try await  block()
                }
                try Task.checkCancellation() //取消报错
                await MainActor.run {
                    if isLoading {
                        hideLoadPopup()
                    }
                    showLog(self.tag, "请求成功：\(result)")
                    suc(result)
                }
            } catch let error {
                if isLoading {
                    hideLoadPopup()
                }
                //DispatchQueue.main.async { //异步的，它不会阻塞当前线程，不适合在这里使用
                await MainActor.run { //同步主线程
                    let exception = self.dealError(error)
                    if exception.code == ERROR.TASK_CANCEL.rawValue {
                        //如果是取消，则不回调
                        return
                    }
                    fail(exception)
                }
            }
        }
        taskManager.addTask(task: task)
    }
    
    public func requestList<T>(
        isRefresh: Bool = false,
        timeout: TimeInterval = 10,
        block: @escaping () async throws-> [T],
        suc: @escaping ([T]) ->Void,
        fail:@escaping(ServerException) -> Void
    ) {
        requestList(isRefresh: isRefresh, block: block, noMore : {
            return $0.count < self.pageSize
        }, suc: suc, fail: fail)
    }
    
    //用于请求列表，自动计算分页
    public func requestList<T>(
        isRefresh: Bool = false,
        timeout: TimeInterval = 10,
        block: @escaping () async throws-> [T],
        noMore: @escaping ([T]) -> Bool,
        suc: @escaping ([T]) ->Void,
        fail:@escaping(ServerException) -> Void
    ) {
        request(isLoading: false) {
            if self.footerRefreshing == false {
                await MainActor.run { //同步主线程
                    self.noMore = false
                    self.footerRefreshing = true
                }
            }
            if isRefresh {
                self.resetPage()
            }
            let result =  try await block()
            return result
        } suc: { list in
            self.addPage()
            self.noMore = noMore(list)
            //如果数据为空，但是没有关闭加载功能，则直接自动请求下一次接口，不在重新绘制LoadMore试图
            if self.noMore == false && list.isEmpty {
                self.requestList(
                    isRefresh: false,
                    timeout: timeout,
                    block: block,
                    noMore: noMore,
                    suc: suc,
                    fail: fail
                )
            } else {
                self.footerRefreshing = false
                suc(list)
            }
            
        } fail: {
            self.footerRefreshing = false
            fail($0)
        }
    }
    
    
    //取消所有的请求
    public func cancelRequest() {
        showLog(self.tag, "执行取消请求")
        taskManager.cancelAllTasks()
    }
    
    //重置页数
    public func resetPage() {
        pageNo = 0
    }
    
    public func addPage() {
        pageNo = pageNo + 1
    }
    
    deinit {
        cancelRequest()
    }
    
    func dealError(_ error: Error) -> ServerException {
        var serverException : ServerException? = nil
        switch error {
        case _ as CancellationError:
            serverException = ServerException(code: ERROR.TASK_CANCEL.rawValue, message: "取消")
        case _ as LCError:
            serverException = ServerException(code: ERROR.LC_ERRPR.rawValue, message: "网络异常")
        case let error as MyError:
            switch error {
            case .Timeout:
                serverException = ServerException(code: ERROR.TIMEOUT_ERROR.rawValue, message: "超时")
            case .invalidParameter(let value):
                serverException = ServerException(code: ERROR.TIMEOUT_ERROR.rawValue, message: value)
            case .getJsonFaild:
                serverException = ServerException(code: ERROR.PARSE_ERROR.rawValue, message: "解析错误")
            case .netFail(let code,let value):
                let exception : ServerException
                switch code {
                case 429:
                    exception = ServerException(code: code, message: "网络异常")
                default:
                    exception = ServerException(code: ERROR.NET_ERRPR.rawValue, message: "网络异常")
                }
                exception.realMessage = value
                serverException = exception
            case .checkParameter(let tag, let value):
                let exception =  ServerException(code: ERROR.CHECK_ERRPR.rawValue, message: value)
                exception.tag = tag
                serverException = exception
            case .customize(let code,let value):
                serverException = ServerException(code: code, message: value)
            default:
                serverException = ServerException(code: ERROR.UNKNOWN.rawValue, message: "异常")
            }
        default:
            serverException = ServerException(code: ERROR.UNKNOWN.rawValue, message: "异常")
        }
        
        if let exception = serverException {
            let logTag = exception.tag ?? self.tag
            showLog(logTag, "请求报错：\(error)")
        }
        return serverException ?? ServerException(code: ERROR.UNKNOWN.rawValue, message: "异常")
        
    }
    
}
